# -*- coding: utf-8 -*-

#
# peerscape.http.controllers.admin
#
# Copyright 2008 Helsinki Institute for Information Technology
# and the authors.
#
# Authors:
#       Konrad Markus <konrad.markus@hiit.fi>
#

# Permission is hereby granted, free of charge, to any person
# obtaining a copy of this software and associated documentation files
# (the "Software"), to deal in the Software without restriction,
# including without limitation the rights to use, copy, modify, merge,
# publish, distribute, sublicense, and/or sell copies of the Software,
# and to permit persons to whom the Software is furnished to do so,
# subject to the following conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

from __future__ import with_statement

import time
import urllib
import os.path
from binascii import unhexlify

from webob import Response
from webob.exc import HTTPMovedPermanently

from peerscape import VERSION
from peerscape import PATH
from peerscape.http.controllers import BaseController
from peerscape.http.color import get_safety_color
from peerscape.core.policy import Unauthorized
from peerscape.sync import report_sync_sessions
from peerscape.profile.application import update_content_from_application, request_content_from_application, autoinstantiate

class Admin(BaseController):
    def __init__(self):
        super(Admin, self).__init__()

    def index(self, req):
        # test to see if we have a persona
        v = {}
        db = req.environ['peerscape.db']
        self.init_translation(db)
        v['global_props'] = self.get_global_props(db)
        v['safety_color'] = get_safety_color(db)

        try:
            my_iid = db.get_my_iid()
            db.blocking_get(my_iid, '/info/modified')
        except LookupError: # persona not initialized
            # redirect to admin
            redir_url = 'http://admin.hexlabel.net/setup_persona/'
            return HTTPMovedPermanently(location=redir_url)

        # proceed as normal
        view = self.load_view('admin.html')
        if view:
            v['path'] = req.host
            v['db_location'] = os.path.expanduser(PATH)
            v['disk_usage'] = db.get_disk_usage()
            v['num_datasets'] = len(db.list_datasets())
            v['sync_sessions'] = report_sync_sessions()
            v['is_admin_section'] = True
            v['version'] = VERSION

            return view.render(**v)
        else:
            return None


    def setup(self, req):
        view = self.load_view('admin.setup.html')

        if view:
            v = {}
            db = req.environ['peerscape.db']
            self.init_translation(db)
            v['safety_color'] = get_safety_color(db)
            v['code'] = ''
            v['errors'] = False
            v['message'] = ''

            # engage -->
            return view.render(**v)
        else:
            return None


    def import_persona(self, req):
        if req.method == 'POST':
            v = {}
            db = req.environ['peerscape.db']
            self.init_translation(db)
            v['safety_color'] = get_safety_color(db)

            # import persona
            if not req.POST.has_key('code') or not req.POST['code']:
                v['code'] = ''
                v['errors'] = True
                v['message'] = _('Please enter a Recovery Code')

            else:
                try:
                    db.set_persona_from_code(req.POST['code'], req.POST['passphrase'])

                    # redirect to profile page
                    redir_url = 'http://my.hexlabel.net/'
                    return HTTPMovedPermanently(location=redir_url)

                except LookupError:
                    v['code'] = req.POST['code']
                    v['errors'] = True
                    v['message'] = _('No such account')
                except Exception, e:
                    v['code'] = req.POST['code']
                    v['errors'] = True
                    v['message'] = _('Connection error. Please try again later. (%s)' % e)

            view = self.load_view('admin.import_persona.html')
            if view:
                # engage -->
                return view.render(**v)
            else:
                return None

        else:
            view = self.load_view('admin.import_persona.html')

            if view:
                v = {}
                db = req.environ['peerscape.db']
                self.init_translation(db)
                v['safety_color'] = get_safety_color(db)
                v['code'] = ''
                v['errors'] = False
                v['message'] = ''

                # engage -->
                return view.render(**v)
            else:
                return None


    def setup_persona(self, req):
        if req.method == 'POST':
            v = {}
            db = req.environ['peerscape.db']
            self.init_translation(db)
            v['safety_color'] = get_safety_color(db)

            try:
                # make sure no persona exists
                iid = db.get_my_iid()

                # get current user iid and redirect
                redir_url = 'http://%s.hexlabel.net/person/' % iid
                return HTTPMovedPermanently(location=redir_url)
            except LookupError: # persona not initialized
                pass

            # create new persona
            v['name'] = req.POST['name']
            if not req.POST.has_key('name') or not req.POST['name']:
                v['errors'] = True
                v['message'] = _('Please enter a name')

                view = self.load_view('admin.setup_persona.html')
                if view:
                    # engage
                    return view.render(**v)
                else:
                    return None

            else:
                iid = db.init_persona(req.POST['name'])

                # try to automatically attach a wall content instance to a new profile
                request_content_from_application(db, '93f5f1c52c5f43a29102cf0b06197d863b85518d', _('My Wall'), public=False)

                # if have invitation code enter that, this will fail silently
                if req.POST.get('invitecode'):
                    try:
                        inviter = db.fetch_invitation_and_make_pending(req.POST.get('invitecode'))
                        invitation = self.get_invitation(db, inviter, force_refresh=True)
                        assert invitation

                        self._expand_invitations_rep(db)
                        db.subscribe(invitation['iid'])
                    except:
                        pass

                # redirect to profile page
                redir_url = 'http://%s.hexlabel.net/person/' % iid
                return HTTPMovedPermanently(location=redir_url)

        else:
            # GET
            view = self.load_view('admin.setup_persona.html')

            if view:
                v = {}
                db = req.environ['peerscape.db']
                self.init_translation(db)
                v['safety_color'] = get_safety_color(db)

                v['errors'] = False
                v['message'] = ''

                # engage -->
                return view.render(**v)
            else:
                return None


    def recovery_code(self, req):
        if req.method == 'POST':
            view = self.load_view('admin.recovery_code.html')

            if view:
                v = {}
                db = req.environ['peerscape.db']
                self.init_translation(db)
                v['global_props'] = self.get_global_props(db)
                v['safety_color'] = get_safety_color(db)
                v['my_iid'] = db.get_my_iid()
                v['recovery_code'] = None
                v['is_admin_section'] = True

                escrow_info = db.get_escrow_info(v['my_iid'])
                if escrow_info:
                    v['recovery_code'] = escrow_info['code']

                if req.POST['passphrase'] != req.POST['passphrase_confirm']:
                    v['errors'] = True
                    v['message'] = _('Passphrase and Passphrase confirm do not match')

                else:
                    v['code'] = db.init_recovery_code(req.POST['passphrase'])
                    v['errors'] = False
                    v['message'] = _('Passphrase set')

                return view.render(**v)
            else:
                return None

        else:
            view = self.load_view('admin.recovery_code.html')

            if view:
                v = {}
                db = req.environ['peerscape.db']
                self.init_translation(db)
                v['global_props'] = self.get_global_props(db)
                v['safety_color'] = get_safety_color(db)
                v['errors'] = False
                v['message'] = ''
                v['my_iid'] = db.get_my_iid()
                v['recovery_code'] = None
                v['is_admin_section'] = True

                escrow_info = db.get_escrow_info(v['my_iid'])
                if escrow_info:
                    v['recovery_code'] = escrow_info['code']

                return view.render(**v)
            else:
                return None


    def groups(self, req):
        view = self.load_view('admin.groups.html')

        if view:
            v = {}
            db = req.environ['peerscape.db']
            self.init_translation(db)
            v['global_props'] = self.get_global_props(db)
            v['safety_color'] = get_safety_color(db)

            v['my_iid'] = db.get_my_iid()
            v['errors'] = False
            v['message'] = ''
            v['errors_groups'] = False
            v['message_groups'] = ''
            v['group_list'] = self.process_group_links_list(db, v['my_iid'])
            v['profile_fields'] = self.process_person_profile(db, v['my_iid'])
            v['ts'] = time.time()
            v['invitecode'] = ''

            if req.POST.has_key('delete_group_link'):
                if req.method == 'POST':
                    if req.POST.has_key('iid') and req.POST['iid']:
                        v['iid'] = req.POST['iid']

                        if req.POST.has_key('warn_yes'):
                            # delete link
                            db.clear_link(v['my_iid'], v['iid'])

                            v['errors_groups'] = False
                            v['message_groups'] = _('Link removed')
                            v['group_list'] = self.process_group_links_list(db, v['my_iid'])
                            return view.render(**v)

                        elif req.POST.has_key('warn_no'):
                            return view.render(**v)
                            
                        else:
                            view = self.load_view('admin.groups_warning.html')
                            v['action'] = 'delete_group_link'
                            v['hash'] = 'groups'
                            v['warning_message'] = _('''You have chosen to remove a link to a group.

                                                    Are you sure you would like to proceed with this?''')
                    else:
                        # ERROR no iid
                        v['errors_groups'] = True
                        v['message_groups'] = _('No iid given')
                        return view.render(**v)
                else:
                    # ERROR not post
                    pass

            if req.POST.has_key('revoke_group'):
                if req.method == 'POST':
                    if req.POST.has_key('iid') and req.POST['iid']:
                        v['iid'] = req.POST['iid']

                        if req.POST.has_key('warn_yes'):
                            db.cancel_membership(v['iid'], v['my_iid'])

                            # delete link
                            db.clear_link(v['my_iid'], v['iid'])

                            v['errors_groups'] = False
                            v['message_groups'] = _('Membership resigned')
                            v['group_list'] = self.process_group_links_list(db, v['my_iid'])
                            return view.render(**v)

                        elif req.POST.has_key('warn_no'):
                            return view.render(**v)
                            
                        else:
                            view = self.load_view('admin.groups_warning.html')
                            v['action'] = 'revoke_group'
                            v['hash'] = 'groups'
                            v['warning_message'] = _('''You have chosen to resign from a group.

                                                    Are you sure you would like to proceed with this?''')
                    else:
                        # ERROR no iid
                        v['errors_groups'] = True
                        v['message_groups'] = _('No iid given')
                        return view.render(**v)
                else:
                    # ERROR not post
                    pass

            if req.POST.has_key('make_group_public'):
                if req.method == 'POST':
                    if req.POST.has_key('iid') and req.POST['iid']:
                        giid = req.POST['iid']
                        # MAKE PUBLIC
                        link = v['group_list']['items'][giid]['link']

                        # get any extras in the link
                        extras = dict([(key,val) for key,val in link.items() if not key in ('iid', 'type', 'public', 'title')])
                        db.add_link(v['my_iid'], giid, public=True, extra_info=extras)

                        v['errors_groups'] = False
                        v['message_groups'] = 'Link made public'
                        v['group_list'] = self.process_group_links_list(db, v['my_iid'])
                        return view.render(**v)

                    else:
                        # ERROR no iid
                        v['errors_groups'] = True
                        v['message_groups'] = _('No iid given')
                        return view.render(**v)
                else:
                    # ERROR not post
                    pass

            if req.POST.has_key('make_group_private'):
                if req.method == 'POST':
                    if req.POST.has_key('iid') and req.POST['iid']:
                        giid = req.POST['iid']
                        # MAKE PRIVATE
                        link = v['group_list']['items'][giid]['link']

                        # get any extras in the link
                        extras = dict([(key,val) for key,val in link.items() if not key in ('iid', 'type', 'public', 'title')])
                        db.add_link(v['my_iid'], giid, public=False, extra_info=extras)

                        v['errors_groups'] = False
                        v['message_groups'] = _('Link made "friends only"')
                        v['group_list'] = self.process_group_links_list(db, v['my_iid'])
                        return view.render(**v)

                    else:
                        # ERROR no iid
                        v['errors_groups'] = True
                        v['message_groups'] = _('No iid given')
                        return view.render(**v)
                else:
                    # ERROR not post
                    pass


            v['errors_groups'] = False
            v['message_groups'] = ''

            return view.render(**v)
        else:
            return None



    def friends(self, req):
        view = self.load_view('admin.friends.html')

        if view:
            v = {}
            db = req.environ['peerscape.db']
            self.init_translation(db)
            v['global_props'] = self.get_global_props(db)
            v['safety_color'] = get_safety_color(db)

            v['my_iid'] = db.get_my_iid()
            v['errors'] = False
            v['message'] = ''
            v['errors_pending'] = False
            v['message_pending'] = ''
            v['errors_friends'] = False
            v['message_friends'] = ''
            v['profile_fields'] = self.process_person_profile(db, v['my_iid'])
            v['friend_list'] = self.process_friend_list(db, v['my_iid'])
            v['ts'] = time.time()

            if req.POST.has_key('revoke_friend'):
                if req.method == 'POST':
                    if req.POST.has_key('iid') and req.POST['iid']:
                        v['iid'] = req.POST['iid']

                        if req.POST.has_key('warn_yes'):
                            db.cancel_friendship(v['iid'])
                            v['errors_friends'] = False
                            v['message_friends'] = _('Friendship revoked')
                            v['friend_list'] = self.process_friend_list(db, v['my_iid'])
                            return view.render(**v)

                        elif req.POST.has_key('warn_no'):
                            return view.render(**v)
                            
                        else:
                            view = self.load_view('admin.friends_warning.html')
                            v['action'] = 'revoke_friend'
                            v['hash'] = 'friends'
                            v['warning_message'] = _('''You have chosen to revoke a friend.

                                                    Are you sure you would like to proceed with this?''')
                    else:
                        # ERROR no iid
                        v['errors_friends'] = True
                        v['message_friends'] = _('No iid given')
                        return view.render(**v)
                else:
                    # ERROR not post
                    pass

            v['errors_friends'] = False
            v['message_friends'] = ''

            return view.render(**v)
        else:
            return None
                                

    def invite_person(self, req):
        if req.method == 'POST':
            view = self.load_view('admin.invite_person.html')

            if view:
                v = {}
                db = req.environ['peerscape.db']
                self.init_translation(db)
                v['global_props'] = self.get_global_props(db)
                v['safety_color'] = get_safety_color(db)
                v['my_iid'] = db.get_my_iid()
                v['profile_fields'] = self.process_person_profile(db, v['my_iid'])
                v['your_name'] = db.get_profile_name(v['my_iid'])
                v['their_name'] = req.POST.get('name')

                v['iid'] = req.POST.get('iid')
                if v['iid']:
                    v['their_name'] = db.get_profile_name(v['iid'])

                v['code'] = db.create_friendship_invitation_code()
                v['email'] = req.POST.get('email')
                v['from_iid'] = req.POST.get('from_iid')
                v['show_invitation'] = True

                email = self.load_view('admin.invite_person_email.txt')
                if email:
                    v['inviteEmailText'] = email.render(**v)
                    v['inviteEmailTextEscaped'] = urllib.quote(v['inviteEmailText'])

                return view.render(**v)
            else:
                return None

        else:
            # GET
            view = self.load_view('admin.invite_person.html')

            if view:
                v = {}
                db = req.environ['peerscape.db']
                self.init_translation(db)
                v['global_props'] = self.get_global_props(db)
                v['safety_color'] = get_safety_color(db)
                v['my_iid'] = db.get_my_iid()
                v['profile_fields'] = self.process_person_profile(db, v['my_iid'])
                v['show_invitation'] = False

                return view.render(**v)
            else:
                return None


    def group_content(self, req):
        if req.method == 'POST':
            view = self.load_view('admin.group_content.html')
            if view:
                v = {}
                db = req.environ['peerscape.db']
                self.init_translation(db)
                v['global_props'] = self.get_global_props(db)
                v['safety_color'] = get_safety_color(db)
                v['my_iid'] = db.get_my_iid()
                v['iid'] = req.POST.get('liid')
                if not v['iid']:
                    return None

                v['hexlabel'] = v['iid']

                v['profile_fields'] = self.process_group_profile(db, v['iid'])
                v['content_list'] = self.process_content_list(db, v['iid'])
                v['member_list'] = self.process_member_list(db, v['iid'], v['my_iid'])
                
                v['is_member'] = v['my_iid'] in v['member_list']['index']
                v['is_admin'] = v['is_member'] and 'admin' in v['member_list']['items'][v['my_iid']]['roles']

                if not v['is_admin']:
                    view = self.load_view('admin.permission_denied.html')
                    return view.render(**v)

                if req.POST.has_key('update_group_content'):
                    if req.POST.has_key('warn_yes'):
                        if req.POST.get('appiid'):
                            appiid = req.POST['appiid']

                            v['errors'] = False
                            v['message'] = _('Updated')

                            for ciid in v['content_list']['items']:
                                # call update in each item
                                if v['content_list']['items'][ciid]['application']['iid'] == appiid and v['content_list']['items'][ciid]['update']:
                                    new_version = update_content_from_application(db, appiid, ciid, db.get(ciid, '/info/parent'))
                                    v['content_list']['items'][ciid]['system']['version'] = new_version
                                    v['content_list']['items'][ciid]['update'] = False

                            v['content_list']['app_meta'][appiid]['update'] = False

                            return view.render(**v)
                        else:
                            # ERROR no appiid
                            v['errors'] = True
                            v['message'] = _('No appiid given')
                            return view.render(**v)

                    elif req.POST.has_key('warn_no'):
                        return view.render(**v)
                        
                    else:
                        view = self.load_view('admin.group_content_warning.html')
                        v['appiid'] = req.POST['appiid']
                        v['liid'] = req.POST['liid']
                        v['ciid'] = ''
                        v['action'] = 'update_group_content'
                        v['warning_message'] = _('''You have chosen to update content items.

                                                Are you sure you would like to proceed with this?''')

                        return view.render(**v)

                if req.POST.has_key('make_group_content_public'):
                    if req.POST.get('ciid') and req.POST.get('liid'):
                        ciid = req.POST['ciid']
                        liid = req.POST['liid']

                        # MAKE PUBLIC
                        link = v['content_list']['items'][ciid]['link']

                        # get any extras in the link
                        extras = dict([(key,val) for key,val in link.items() if not key in ('iid', 'public', 'title')])
                        db.add_link(liid, ciid, public=True, extra_info=extras)

                        v['errors'] = False
                        v['message'] = _('Link made public')
                        v['content_list'] = self.process_content_list(db, v['iid'])
                        return view.render(**v)

                    else:
                        # ERROR no iid
                        v['errors'] = True
                        v['message'] = _('No iid given')
                        return view.render(**v)


                if req.POST.has_key('make_group_content_private'):
                    if req.POST.get('ciid') and req.POST.get('liid'):
                        ciid = req.POST['ciid']
                        liid = req.POST['liid']

                        # MAKE PRIVATE
                        link = v['content_list']['items'][ciid]['link']

                        # get any extras in the link
                        extras = dict([(key,val) for key,val in link.items() if not key in ('iid', 'type', 'public', 'title')])
                        db.add_link(liid, ciid, public=False, extra_info=extras)

                        v['errors'] = False
                        v['message'] = _('Link made "friends only"')
                        v['content_list'] = self.process_content_list(db, v['iid'])
                        return view.render(**v)

                    else:
                        # ERROR no iid
                        v['errors'] = True
                        v['message'] = _('No iid given')
                        return view.render(**v)


                if req.POST.has_key('delete_group_content'):
                    if req.POST.has_key('warn_yes'):
                        if req.POST.get('ciid') and req.POST.get('liid'):
                            ciid = req.POST['ciid']
                            liid = req.POST['liid']

                            # delete all dataset data
                            ls = db.list(ciid)
                            with db.write_transaction():
                                for k in ls:
                                    db.delete(ciid, k)

                            # Remove link from profile
                            db.clear_link(liid, ciid)

                            v['message'] = _('Content deleted')
                            v['content_list'] = self.process_content_list(db, v['iid'])
                            return view.render(**v)
                        else:
                            # ERROR no iid
                            v['errors'] = True
                            v['message'] = _('No iid given')
                            return view.render(**v)

                    elif req.POST.has_key('warn_no'):
                        return view.render(**v)
                        
                    else:
                        view = self.load_view('admin.group_content_warning.html')
                        v['ciid'] = req.POST['ciid']
                        v['liid'] = req.POST['liid']
                        v['appiid'] = ''
                        v['action'] = 'delete_group_content'
                        v['warning_message'] = _('''You have chosen to delete this content completely.

                                                Are you sure you would like to proceed with this?''')

                return view.render(**v)
            else:
                return None
        else:
            # GET
            v = {}
            db = req.environ['peerscape.db']
            self.init_translation(db)
            v['global_props'] = self.get_global_props(db)
            v['safety_color'] = get_safety_color(db)
            v['my_iid'] = db.get_my_iid()
            v['iid'] = req.GET.get('iid')
            if not v['iid']:
                return None

            v['hexlabel'] = v['iid']
            v['profile_fields'] = self.process_group_profile(db, v['iid'])
            v['content_list'] = self.process_content_list(db, v['iid'])
            v['member_list'] = self.process_member_list(db, v['iid'], v['my_iid'])
            
            v['is_member'] = v['my_iid'] in v['member_list']['index']
            v['is_admin'] = v['is_member'] and 'admin' in v['member_list']['items'][v['my_iid']]['roles']

            if v['is_admin']:
                view = self.load_view('admin.group_content.html')
            else:
                view = self.load_view('admin.permission_denied.html')

            return view.render(**v)


    def content(self, req):
        if req.method == 'POST':
            view = self.load_view('admin.content.html')

            if view:
                v = {}
                db = req.environ['peerscape.db']
                self.init_translation(db)
                v['global_props'] = self.get_global_props(db)
                v['safety_color'] = get_safety_color(db)
                v['my_iid'] = db.get_my_iid()
                v['profile_fields'] = self.process_person_profile(db, v['my_iid'])
                v['content_list'] = self.process_content_list(db, v['my_iid'])

                if req.POST.has_key('update_content'):
                    if req.POST.has_key('warn_yes'):
                        if req.POST.get('appiid'):
                            appiid = req.POST['appiid']

                            v['errors'] = False
                            v['message'] = _('Updated')

                            for ciid in v['content_list']['items']:
                                # call update in each item
                                if v['content_list']['items'][ciid]['application']['iid'] == appiid and v['content_list']['items'][ciid]['update']:
                                    new_version = update_content_from_application(db, appiid, ciid, db.get(ciid, '/info/parent'))
                                    v['content_list']['items'][ciid]['system']['version'] = new_version
                                    v['content_list']['items'][ciid]['update'] = False

                            v['content_list']['app_meta'][appiid]['update'] = False

                            return view.render(**v)

                        else:
                            # ERROR no appiid
                            v['errors'] = True
                            v['message'] = _('No appiid given')
                            return view.render(**v)

                    elif req.POST.has_key('warn_no'):
                        return view.render(**v)
                        
                    else:
                        view = self.load_view('admin.content_warning.html')
                        v['appiid'] = req.POST.get('appiid')
                        v['liid'] = ''
                        v['ciid'] = ''
                        v['action'] = 'update_content'
                        v['warning_message'] = _('''You have chosen to update content items.

                                                Are you sure you would like to proceed with this?''')

                        return view.render(**v)

                if req.POST.has_key('make_content_public'):
                    if req.POST.get('ciid') and req.POST.get('liid'):
                        ciid = req.POST['ciid']
                        liid = req.POST['liid']

                        # MAKE PUBLIC
                        link = v['content_list']['items'][ciid]['link']

                        # get any extras in the link
                        extras = dict([(key,val) for key,val in link.items() if not key in ('iid', 'public', 'title')])
                        db.add_link(liid, ciid, public=True, extra_info=extras)

                        v['errors'] = False
                        v['message'] = _('Link made public')
                        v['content_list'] = self.process_content_list(db, v['my_iid'])
                        return view.render(**v)

                    else:
                        # ERROR no iid
                        v['errors'] = True
                        v['message'] = _('No iid given')
                        return view.render(**v)


                if req.POST.has_key('make_content_private'):
                    if req.POST.get('ciid') and req.POST.get('liid'):
                        ciid = req.POST['ciid']
                        liid = req.POST['liid']

                        # MAKE PRIVATE
                        link = v['content_list']['items'][ciid]['link']

                        # get any extras in the link
                        extras = dict([(key,val) for key,val in link.items() if not key in ('iid', 'type', 'public', 'title')])
                        db.add_link(liid, ciid, public=False, extra_info=extras)

                        v['errors'] = False
                        v['message'] = _('Link made "friends only"')
                        v['content_list'] = self.process_content_list(db, v['my_iid'])
                        return view.render(**v)

                    else:
                        # ERROR no iid
                        v['errors'] = True
                        v['message'] = _('No iid given')
                        return view.render(**v)


                if req.POST.has_key('delete_content'):
                    if req.POST.has_key('warn_yes'):
                        if req.POST.get('ciid') and req.POST.get('liid'):
                            ciid = req.POST['ciid']
                            liid = req.POST['liid']

                            # delete all dataset data
                            ls = db.list(ciid)
                            with db.write_transaction():
                                for k in ls:
                                    db.delete(ciid, k)

                            # Remove link from profile
                            db.clear_link(liid, ciid)

                            v['message'] = _('Content deleted')
                            v['content_list'] = self.process_content_list(db, v['my_iid'])
                            return view.render(**v)
                        else:
                            # ERROR no iid
                            v['errors'] = True
                            v['message'] = _('No iid given')
                            return view.render(**v)

                    elif req.POST.has_key('warn_no'):
                        return view.render(**v)
                        
                    else:
                        view = self.load_view('admin.content_warning.html')
                        v['ciid'] = req.POST.get('ciid')
                        v['liid'] = req.POST.get('liid')
                        v['appiid'] = ''
                        v['action'] = 'delete_content'
                        v['warning_message'] = _('''You have chosen to delete this content completely.

                                                Are you sure you would like to proceed with this?''')

                return view.render(**v)
            else:
                return None
        else:
            # GET
            view = self.load_view('admin.content.html')

            if view:
                v = {}
                db = req.environ['peerscape.db']
                self.init_translation(db)
                v['global_props'] = self.get_global_props(db)
                v['safety_color'] = get_safety_color(db)
                v['my_iid'] = db.get_my_iid()
                v['profile_fields'] = self.process_person_profile(db, v['my_iid'])
                v['content_list'] = self.process_content_list(db, v['my_iid'], all_content=True)

                return view.render(**v)
            else:
                return None


    def invite_group(self, req):
        if req.method == 'POST':
            view = self.load_view('admin.invite_group.html')

            if view:
                v = {}
                db = req.environ['peerscape.db']
                self.init_translation(db)
                v['global_props'] = self.get_global_props(db)
                v['safety_color'] = get_safety_color(db)
                v['my_iid'] = db.get_my_iid()

                v['email'] = req.POST.get('email')
                v['iid'] = req.POST.get('iid')
                if not v['iid']:
                    return None

                v['group_name'] = db.get_profile_name(v['iid'])
                v['your_name'] = db.get_profile_name(v['my_iid'])
                v['their_name'] = req.POST.get('name')

                # just for convenience
                v['hexlabel'] = v['iid']

                v['profile_fields'] = self.process_group_profile(db, v['iid'])
                v['member_list'] = self.process_member_list(db, v['iid'], v['my_iid'])
                
                v['is_member'] = v['my_iid'] in v['member_list']['index']
                v['is_admin'] = v['is_member'] and 'admin' in v['member_list']['items'][v['my_iid']]['roles']

                v['code'] = db.create_membership_invitation_code(v['iid'])
                v['show_invitation'] = True

                email = self.load_view('admin.invite_group_email.txt')
                if email:
                    v['inviteEmailText'] = email.render(**v)
                    v['inviteEmailTextEscaped'] = urllib.quote(v['inviteEmailText'])

                return view.render(**v)
            else:
                return None

        else:
            # GET
            view = self.load_view('admin.invite_group.html')

            if view:
                v = {}
                db = req.environ['peerscape.db']
                self.init_translation(db)
                v['global_props'] = self.get_global_props(db)
                v['safety_color'] = get_safety_color(db)
                v['my_iid'] = db.get_my_iid()
                v['iid'] = req.GET.get('iid')
                if not v['iid']:
                    return None

                # just for convenience
                v['hexlabel'] = v['iid']

                v['profile_fields'] = self.process_group_profile(db, v['iid'])
                v['member_list'] = self.process_member_list(db, v['iid'], v['my_iid'])
                
                v['is_member'] = v['my_iid'] in v['member_list']['index']
                v['is_admin'] = v['is_member'] and 'admin' in v['member_list']['items'][v['my_iid']]['roles']

                v['show_invitation'] = False

                return view.render(**v)
            else:
                return None
        
        
    def create_dataset(self, req):
        if req.method == 'POST':
            view = self.load_view('admin.create_dataset.html')

            if view:
                v = {}
                db = req.environ['peerscape.db']
                self.init_translation(db)
                v['global_props'] = self.get_global_props(db)
                v['safety_color'] = get_safety_color(db)
                v['errors'] = False
                v['message'] = ''
                v['created'] = False
                v['my_iid'] = db.get_my_iid()
                v['is_admin_section'] = True

                # update name
                v['name'] = (req.POST.get('name') or '').strip()
                if not v['name']:
                    v['type'] = (req.POST.get('type') or '').strip()
                    v['errors'] = True
                    v['message'] = _('Please enter a name')
                    return view.render(**v)

                v['type'] = (req.POST.get('type') or '').strip()
                if not v['type']:
                    v['errors'] = True
                    v['message'] = _('Please enter a type')
                    return view.render(**v)

                if v['type'] == 'principal' or v['type'] == 'group':
                    v['errors'] = True
                    v['message'] = _('Please do not use "principal" or "group" for the type')
                    return view.render(**v)

                # create dataset
                try:
                    v['dataset_iid'] = db.create_dataset(v['name'], type=v['type'])

                except (Unauthorized, LookupError):
                    v['errors'] = True
                    v['message'] = _('Could not create dataset at this time.')
                    return view.render(**v)

                v['created'] = True
                return view.render(**v)
            else:
                return None

        else:
            # GET
            view = self.load_view('admin.create_dataset.html')

            if view:
                v = {}
                db = req.environ['peerscape.db']
                self.init_translation(db)
                v['global_props'] = self.get_global_props(db)
                v['safety_color'] = get_safety_color(db)
                v['errors'] = False
                v['message'] = ''
                v['created'] = False
                v['my_iid'] = db.get_my_iid()
                v['is_admin_section'] = True

                v['name'] = '';
                v['type'] = '';

                # engage -->
                return view.render(**v)
            else:
                return None

        
    def create_group(self, req):
        if req.method == 'POST':
            view = self.load_view('admin.create_group.html')

            if view:
                v = {}
                db = req.environ['peerscape.db']
                self.init_translation(db)
                v['global_props'] = self.get_global_props(db)
                v['safety_color'] = get_safety_color(db)
                v['errors'] = False
                v['message'] = ''
                v['my_iid'] = db.get_my_iid()

                # get the generic fields
                generic_fields = dict([(key,val) for key,val in req.POST.items() if key.startswith('generic')])

                # update name
                if not generic_fields.get('generic:0:name'):
                    v['profile_fields'] = self.process_group_profile(db, iid=None)
                    v['profile_fields']['generic']['name']['values'][0]['value'] = ''
                    v['profile_fields']['generic']['about']['values'][0]['value'] = generic_fields.get('generic:0:about')
                    v['errors'] = True
                    v['message'] = _('Please enter a name')
                    return view.render(**v)

                name = (generic_fields['generic:0:name'] or '').strip()

                # create group
                try:
                    iid = db.create_group(name)

                    if generic_fields.get('generic:0:about'):
                        # update about
                        db.set_profile_text(iid, generic_fields['generic:0:about'] or '', public=True)

                except (Unauthorized, LookupError):
                    v['errors'] = True
                    v['message'] = _('Could not create group at this time.')
                    return view.render(**v)

                # get the public link flag
                public_link = (req.POST.get('public_link') == 'on')

                # create link
                db.add_link(v['my_iid'], iid, public=public_link)

                # redirect to profile
                redir_url = 'http://%s.hexlabel.net/group/' % iid
                return HTTPMovedPermanently(location=redir_url)
            else:
                return None

        else:
            # GET
            view = self.load_view('admin.create_group.html')

            if view:
                v = {}
                db = req.environ['peerscape.db']
                self.init_translation(db)
                v['global_props'] = self.get_global_props(db)
                v['safety_color'] = get_safety_color(db)
                v['errors'] = False
                v['message'] = ''
                v['my_iid'] = db.get_my_iid()

                # get profile (iid=None means it's empty)
                v['profile_fields'] = self.process_group_profile(db, iid=None)
                v['profile_fields']['generic']['name']['values'][0]['value'] = ''

                # engage -->
                return view.render(**v)
            else:
                return None

        
    def manage_group(self, req):
        if req.method == 'POST':
            view = self.load_view('admin.manage_group.html')

            if view:
                v = {}
                db = req.environ['peerscape.db']
                self.init_translation(db)
                v['global_props'] = self.get_global_props(db)
                v['safety_color'] = get_safety_color(db)
                v['errors'] = False
                v['message'] = ''
                v['my_iid'] = db.get_my_iid()
                v['iid'] = req.POST.get('iid')
                if not v['iid']:
                    return None

                # just for convenience
                v['hexlabel'] = v['iid']

                # get multiple (checkbox) values
                v['miid_list'] = req.POST.getall('miid')

                v['profile_fields'] = self.process_group_profile(db, v['iid'])
                v['member_list'] = self.process_member_list(db, v['iid'], v['my_iid'])
                v['content_list'] = self.process_content_list(db, v['iid'])
                
                v['is_member'] = v['my_iid'] in v['member_list']['index']
                v['is_admin'] = v['is_member'] and 'admin' in v['member_list']['items'][v['my_iid']]['roles']

                if v['is_admin']:
                    # content actions
                    if req.POST.has_key('make_content_public'):
                        if req.POST.get('ciid'):
                            ciid = req.POST['ciid']
                            # MAKE PUBLIC
                            link = v['content_list']['items'][ciid]['link']

                            # get any extras in the link
                            extras = dict([(key,val) for key,val in link.items() if not key in ('iid', 'public', 'title')])
                            db.add_link(v['hexlabel'], ciid, public=True, extra_info=extras)

                            v['errors_content'] = False
                            v['message_content'] = 'Link made public'
                            v['content_list'] = self.process_content_list(db, v['hexlabel'])
                            return view.render(**v)

                        else:
                            # ERROR no iid
                            v['errors_content'] = True
                            v['message_content'] = _('No iid given')
                            return view.render(**v)


                    if req.POST.has_key('make_content_private'):
                        if req.POST.get('ciid'):
                            ciid = req.POST['ciid']
                            # MAKE PRIVATE
                            link = v['content_list']['items'][ciid]['link']

                            # get any extras in the link
                            extras = dict([(key,val) for key,val in link.items() if not key in ('iid', 'type', 'public', 'title')])
                            db.add_link(v['hexlabel'], ciid, public=False, extra_info=extras)

                            v['errors_content'] = False
                            v['message_content'] = 'Link made "friends only"'
                            v['content_list'] = self.process_content_list(db, v['hexlabel'])
                            return view.render(**v)

                        else:
                            # ERROR no iid
                            v['errors_content'] = True
                            v['message_content'] = _('No iid given')
                            return view.render(**v)


                    if req.POST.has_key('delete_content'):
                        if req.POST.has_key('warn_yes'):
                            if req.POST.get('ciid'):
                                ciid = req.POST['ciid']

                                # delete all dataset data
                                ls = db.list(ciid)
                                with db.write_transaction():
                                    for k in ls:
                                        db.delete(ciid, k)

                                # Remove link from profile
                                db.clear_link(v['hexlabel'], ciid)

                                v['errors_content'] = False
                                v['message_content'] = 'Content deleted'
                                v['content_list'] = self.process_content_list(db, v['hexlabel'])
                                return view.render(**v)
                            else:
                                # ERROR no iid
                                v['errors'] = True
                                v['message'] = _('No iid given')
                                return view.render(**v)

                        elif req.POST.has_key('warn_no'):
                            return view.render(**v)
                            
                        else:
                            view = self.load_view('admin.manage_group_warning.html')
                            v['section'] = 'mycontent'
                            v['ciid'] = req.POST.get('ciid')
                            v['action'] = 'delete_content'
                            v['warning_message'] = '''You have chosen to delete this content completely.

                                                    Are you sure you would like to proceed with this?'''


                    # member related actions
                    if len(v['miid_list']) > 0:
                        if req.POST.has_key('grant_author'):
                            for miid in v['miid_list']:
                                info = db.get_json(v['iid'], '/auth/' + miid)
                                roles = info.get('roles', [])
                                if not 'author' in roles:
                                    roles.append('author')

                                db.update_json(v['iid'], '/auth/' + miid, roles=roles)

                            v['message'] = _('Author role granted')
                            v['member_list'] = self.process_member_list(db, v['iid'], v['my_iid'])
                            return view.render(**v)

                        if req.POST.has_key('revoke_author'):
                            if req.POST.has_key('warn_yes'):
                                for miid in v['miid_list']:
                                    info = db.get_json(v['iid'], '/auth/' + miid)
                                    roles = info.get('roles', [])
                                    if 'author' in roles:
                                        roles = [x for x in roles if not x == 'author']

                                    db.update_json(v['iid'], '/auth/' + miid, roles=roles)

                                v['message'] = _('Author role revoked')
                                v['member_list'] = self.process_member_list(db, v['iid'], v['my_iid'])
                                return view.render(**v)

                            elif req.POST.has_key('warn_no'):
                                return view.render(**v)
                                
                            else:
                                view = self.load_view('admin.manage_group_warning.html')
                                v['section'] = 'members'
                                v['ciid'] = ''
                                v['action'] = 'revoke_author'
                                v['warning_message'] = _('''You have chosen to revoke the Author role for one or more members.

                                                        Are you sure you would like to proceed with this?''')

                        if req.POST.has_key('grant_admin'):
                            for miid in v['miid_list']:
                                info = db.get_json(v['iid'], '/auth/' + miid)
                                roles = info.get('roles', [])
                                if not 'admin' in roles:
                                    roles.append('admin')

                                db.update_json(v['iid'], '/auth/' + miid, roles=roles)

                            v['message'] = _('Admin role granted')
                            v['member_list'] = self.process_member_list(db, v['iid'], v['my_iid'])
                            return view.render(**v)

                        if req.POST.has_key('revoke_admin'):
                            if req.POST.has_key('warn_yes'):
                                for miid in v['miid_list']:
                                    info = db.get_json(v['iid'], '/auth/' + miid)
                                    roles = info.get('roles', [])
                                    if 'admin' in roles:
                                        roles = [x for x in roles if not x == 'admin']

                                    db.update_json(v['iid'], '/auth/' + miid, roles=roles)

                                if v['my_iid'] in v['miid_list']:
                                    # revoked own admin role, re-direct to group profile
                                    redir_url = 'http://%s.hexlabel.net/' % v['iid']
                                    return HTTPMovedPermanently(location=redir_url)
                                else:
                                    v['message'] = _('Admin role revoked')
                                    v['member_list'] = self.process_member_list(db, v['iid'], v['my_iid'])
                                    return view.render(**v)

                            elif req.POST.has_key('warn_no'):
                                return view.render(**v)
                                
                            else:
                                view = self.load_view('admin.manage_group_warning.html')
                                v['section'] = 'members'
                                v['ciid'] = ''
                                v['action'] = 'revoke_admin'
                                v['warning_message'] = _('''You have chosen to revoke the Admin role for one or more members.

                                                        Are you sure you would like to proceed with this?''')

                        if req.POST.has_key('revoke_membership'):
                            if req.POST.has_key('warn_yes'):
                                for miid in v['miid_list']:
                                    roles = db.cancel_membership(v['iid'], miid)
                                    # NOTE: principal has non-member link to group in profile

                                v['message'] = _('Membership revoked')
                                v['member_list'] = self.process_member_list(db, v['iid'], v['my_iid'])
                                return view.render(**v)

                            elif req.POST.has_key('warn_no'):
                                return view.render(**v)
                                
                            else:
                                view = self.load_view('admin.manage_group_warning.html')
                                v['section'] = 'members'
                                v['ciid'] = ''
                                v['action'] = 'revoke_membership'
                                v['warning_message'] = _('''You have chosen to revoke group membership for one or more members.

                                                        Are you sure you would like to proceed with this?''')

                    else:
                        v['errors'] = True
                        v['message'] = _('No members selected')
                        return view.render(**v)
                        
                else:
                    v['errors'] = True
                    v['message'] = _('Permission denied (%s)') % v['is_member']

                return view.render(**v)

        else:
            # GET
            v = {}
            db = req.environ['peerscape.db']
            self.init_translation(db)
            v['global_props'] = self.get_global_props(db)
            v['safety_color'] = get_safety_color(db)
            v['my_iid'] = db.get_my_iid()
            v['iid'] = req.GET.get('iid')
            if not v['iid']:
                return None

            # just for convenience
            v['hexlabel'] = v['iid']

            v['profile_fields'] = self.process_group_profile(db, v['iid'])
            v['member_list'] = self.process_member_list(db, v['iid'], v['my_iid'])
            v['content_list'] = self.process_content_list(db, v['iid'])
            
            v['is_member'] = v['my_iid'] in v['member_list']['index']
            v['is_admin'] = v['is_member'] and 'admin' in v['member_list']['items'][v['my_iid']]['roles']

            if v['is_admin']:
                view = self.load_view('admin.manage_group.html')
            else:
                view = self.load_view('admin.permission_denied.html')

            if view:
                return view.render(**v)
            else:
                return None

        
    def browse_db(self, req):
        # GET
        v = {}
        db = req.environ['peerscape.db']
        self.init_translation(db)
        v['global_props'] = self.get_global_props(db)
        v['safety_color'] = get_safety_color(db)
        v['my_iid'] = db.get_my_iid()

        v['dataset_list'] = self.process_all_datasets(db)
        v['dataset_iid'] = None

        # get path info if any
        pi = req.path
        if pi:
            pi_segements = pi[1:].split('/')
            v['dataset_iid'] = pi_segements[1]
            v['dataset_path'] = '/'.join(pi_segements[2:])
            v['dataset'] = self.process_dataset(db, v['dataset_iid'])


        view = self.load_view('admin.browse_db.html')
        if view:
            return view.render(**v)
        else:
            return None


